#include <linux/sysrq.h>
#include <asm/irq.h>
#include <asm/mmu_context.h>
-#include <asm-xen/ctrl_if.h>
#include <asm-xen/evtchn.h>
#include <asm-xen/hypervisor.h>
#include <asm-xen/xen-public/dom0_ops.h>
#include <asm-xen/queues.h>
#include <asm-xen/xenbus.h>
+#define SHUTDOWN_INVALID -1
+#define SHUTDOWN_POWEROFF 0
+#define SHUTDOWN_REBOOT 1
+#define SHUTDOWN_SUSPEND 2
+
void machine_restart(char * __unused)
{
/* We really want to get pending console data out before we die. */
*/
/* Ignore multiple shutdown requests. */
-static int shutting_down = -1;
+static int shutting_down = SHUTDOWN_INVALID;
static void __do_suspend(void)
{
xenbus_suspend();
- ctrl_if_suspend();
-
irq_suspend();
gnttab_suspend();
HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT);
- shutting_down = -1;
+ shutting_down = SHUTDOWN_INVALID;
memcpy(&xen_start_info, &suspend_record->resume_info,
sizeof(xen_start_info));
irq_resume();
- ctrl_if_resume();
-
xenbus_resume();
#ifdef CONFIG_SMP
switch ( shutting_down )
{
- case CMSG_SHUTDOWN_POWEROFF:
+ case SHUTDOWN_POWEROFF:
if ( execve("/sbin/poweroff", poweroff_argv, envp) < 0 )
{
sys_reboot(LINUX_REBOOT_MAGIC1,
}
break;
- case CMSG_SHUTDOWN_REBOOT:
+ case SHUTDOWN_REBOOT:
if ( execve("/sbin/reboot", restart_argv, envp) < 0 )
{
sys_reboot(LINUX_REBOOT_MAGIC1,
break;
}
- shutting_down = -1; /* could try again */
+ shutting_down = SHUTDOWN_INVALID; /* could try again */
return 0;
}
{
int err;
- if ( shutting_down != CMSG_SHUTDOWN_SUSPEND )
+ if ( shutting_down != SHUTDOWN_SUSPEND )
{
err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES);
if ( err < 0 )
}
}
-static void shutdown_handler(ctrl_msg_t *msg, unsigned long id)
+static void shutdown_handler(struct xenbus_watch *watch, const char *node)
{
static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
- if ( msg->subtype == CMSG_SHUTDOWN_SYSRQ )
- {
- int sysrq = ((shutdown_sysrq_t *)&msg->msg[0])->key;
-
+ int type = -1;
+
+ if (!xenbus_scanf("control", "shutdown", "%i", &type)) {
+ printk("Unable to read code in control/shutdown\n");
+ return;
+ };
+
+ xenbus_printf("control", "shutdown", "%i", SHUTDOWN_INVALID);
+
+ if ((type == SHUTDOWN_POWEROFF) ||
+ (type == SHUTDOWN_REBOOT) ||
+ (type == SHUTDOWN_SUSPEND)) {
+ shutting_down = type;
+ schedule_work(&shutdown_work);
+ }
+
+}
+
#ifdef CONFIG_MAGIC_SYSRQ
+static void sysrq_handler(struct xenbus_watch *watch, const char *node)
+{
+ char sysrq_key = '\0';
+
+ if (!xenbus_scanf("control", "sysrq", "%c", &sysrq_key)) {
+ printk("Unable to read sysrq code in control/sysrq\n");
+ return;
+ }
+
+ xenbus_printf("control", "sysrq", "%c", '\0');
+
+ if (sysrq_key != '\0') {
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- handle_sysrq(sysrq, NULL, NULL);
+ handle_sysrq(sysrq_key, NULL, NULL);
#else
- handle_sysrq(sysrq, NULL, NULL, NULL);
-#endif
+ handle_sysrq(sysrq_key, NULL, NULL, NULL);
#endif
}
- else if ( (shutting_down == -1) &&
- ((msg->subtype == CMSG_SHUTDOWN_POWEROFF) ||
- (msg->subtype == CMSG_SHUTDOWN_REBOOT) ||
- (msg->subtype == CMSG_SHUTDOWN_SUSPEND)) )
- {
- shutting_down = msg->subtype;
- schedule_work(&shutdown_work);
+}
+#endif
+
+static struct xenbus_watch shutdown_watch = {
+ .node = "control/shutdown",
+ .callback = shutdown_handler
+};
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static struct xenbus_watch sysrq_watch = {
+ .node ="control/sysrq",
+ .callback = sysrq_handler
+};
+#endif
+
+static struct notifier_block xenstore_notifier;
+
+static int setup_shutdown_watcher(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ int err1=0, err2=0;
+
+ down(&xenbus_lock);
+ err1 = register_xenbus_watch(&shutdown_watch);
+#ifdef CONFIG_MAGIC_SYSRQ
+ err2 = register_xenbus_watch(&sysrq_watch);
+#endif
+ up(&xenbus_lock);
+
+ if (err1) {
+ printk("Failed to set shutdown watcher\n");
}
- else
- {
- printk("Ignore spurious shutdown request\n");
+
+#ifdef CONFIG_MAGIC_SYSRQ
+ if (err2) {
+ printk("Failed to set sysrq watcher\n");
}
+#endif
- ctrl_if_send_response(msg);
+ return NOTIFY_STOP;
}
static int __init setup_shutdown_event(void)
{
- ctrl_if_register_receiver(CMSG_SHUTDOWN, shutdown_handler, 0);
+
+ xenstore_notifier.notifier_call = setup_shutdown_watcher;
+
+ if (xen_start_info.store_evtchn) {
+ setup_shutdown_watcher(&xenstore_notifier, 0, NULL);
+ } else {
+ register_xenstore_notifier(&xenstore_notifier);
+ }
+
return 0;
}
-__initcall(setup_shutdown_event);
+subsys_initcall(setup_shutdown_event);
#include <linux/ctype.h>
#include <linux/fcntl.h>
#include <stdarg.h>
+#include <linux/notifier.h>
#include "xenbus_comms.h"
#define streq(a, b) (strcmp((a), (b)) == 0)
+/* Protects notifier chain */
+DECLARE_MUTEX(xenstore_control);
+
+static struct notifier_block *xenstore_chain;
+
/* If something in array of ids matches this device, return it. */
static const struct xenbus_device_id *
match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
up(&xenbus_lock);
}
+int register_xenstore_notifier(struct notifier_block *nb)
+{
+ int ret;
+
+ if ((ret = down_interruptible(&xenstore_control)) != 0)
+ return ret;
+ ret = notifier_chain_register(&xenstore_chain, nb);
+ up(&xenstore_control);
+ return ret;
+}
+EXPORT_SYMBOL(register_xenstore_notifier);
+
+void unregister_xenstore_notifier(struct notifier_block *nb)
+{
+ down(&xenstore_control);
+ notifier_chain_unregister(&xenstore_chain, nb);
+ up(&xenstore_control);
+}
+EXPORT_SYMBOL(unregister_xenstore_notifier);
+
/* called from a thread in privcmd/privcmd.c */
int do_xenbus_probe(void *unused)
{
return err;
}
+ err = notifier_call_chain(&xenstore_chain, 0, 0);
+ if (err == NOTIFY_BAD) {
+ printk("%s: calling xenstore notify chain failed\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+
+ err = 0;
+
/* Initialize non-xenbus drivers */
balloon_init_watcher();
* IN THE SOFTWARE.
*/
#include <linux/device.h>
+#include <linux/notifier.h>
#include <asm/semaphore.h>
/* A xenbus device. */
void (*callback)(struct xenbus_watch *, const char *node);
};
+/* notifer routines for when the xenstore comes up */
+int register_xenstore_notifier(struct notifier_block *nb);
+void unregister_xenstore_notifier(struct notifier_block *nb);
+
int register_xenbus_watch(struct xenbus_watch *watch);
void unregister_xenbus_watch(struct xenbus_watch *watch);
return self.xendPost(self.domainurl(id),
{'op' : 'pause' })
- def xend_domain_shutdown(self, id, reason, key=0):
+ def xend_domain_shutdown(self, id, reason):
return self.xendPost(self.domainurl(id),
{'op' : 'shutdown',
- 'reason' : reason,
- 'key' : key })
+ 'reason' : reason})
+
+ def xend_domain_sysrq(self, id, key):
+ return self.xendPost(self.domainurl(id),
+ {'op' : 'sysrq',
+ 'key' : key})
def xend_domain_destroy(self, id, reason):
return self.xendPost(self.domainurl(id),
except Exception, ex:
raise XendError(str(ex))
- def domain_shutdown(self, id, reason='poweroff', key=0):
+ def domain_shutdown(self, id, reason='poweroff'):
"""Shutdown domain (nicely).
- poweroff: restart according to exit code and restart mode
- reboot: restart on exit
eserver.inject('xend.domain.shutdown', [dominfo.name, dominfo.id, reason])
if reason == 'halt':
reason = 'poweroff'
- val = dominfo.shutdown(reason, key=key)
- if not reason in ['suspend', 'sysrq']:
+ val = dominfo.shutdown(reason)
+ if not reason in ['suspend']:
self.domain_shutdowns()
return val
+ def domain_sysrq(self, id, key):
+ """Send a SysRq to a domain
+ """
+ dominfo = self.domain_lookup(id)
+ val = dominfo.send_sysrq(key)
+ return val
+
def domain_shutdowns(self):
"""Process pending domain shutdowns.
Destroys domains whose shutdowns have timed out.
DOMAIN_CRASH : "crash",
}
-"""Map shutdown reasons to the message type to use.
+"""Map shutdown reasons to codes
"""
-shutdown_messages = {
- 'poweroff' : 'shutdown_poweroff_t',
- 'reboot' : 'shutdown_reboot_t',
- 'suspend' : 'shutdown_suspend_t',
- 'sysrq' : 'shutdown_sysrq_t',
+shutdown_codes = {
+ 'poweroff' : DOMAIN_POWEROFF,
+ 'reboot' : DOMAIN_REBOOT,
+ 'suspend' : DOMAIN_SUSPEND,
}
RESTART_ALWAYS = 'always'
vm = cls(db)
vm.construct(config)
vm.saveToDB(sync=True)
- # Flush info to xenstore immediately
- vm.exportToDB()
return vm
self.channel.writeRequest(msg)
- def shutdown(self, reason, key=0):
- msgtype = shutdown_messages.get(reason)
- if not msgtype:
+ def shutdown(self, reason):
+ reasonid = shutdown_codes.get(reason)
+ if reasonid == None:
raise XendError('invalid reason:' + reason)
- extra = {}
- if reason == 'sysrq':
- extra['key'] = key
- if self.channel:
- msg = messages.packMsg(msgtype, extra)
- self.channel.writeRequest(msg)
- if not reason in ['suspend', 'sysrq']:
- self.shutdown_pending = {'start':time.time(), 'reason':reason,
- 'key':key}
+ db = self.db.addChild("/control");
+ db['shutdown'] = '%i' % reasonid;
+ db.saveDB(save=True);
+ if not reason in ['suspend']:
+ self.shutdown_pending = {'start':time.time(), 'reason':reason}
+
+ def send_sysrq(self, key=0):
+ db = self.db.addChild("/control");
+ db['sysrq'] = '%c' % key;
+ db.saveDB(save=True);
def shutdown_time_left(self, timeout):
if not self.shutdown_pending:
def op_shutdown(self, op, req):
fn = FormFn(self.xd.domain_shutdown,
[['dom', 'int'],
- ['reason', 'str'],
- ['key', 'int']])
+ ['reason', 'str']])
val = fn(req.args, {'dom': self.dom.id})
req.setResponseCode(http.ACCEPTED)
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
+ def op_sysrq(self, op, req):
+ fn = FormFn(self.xd.domain_sysrq,
+ [['dom', 'int'],
+ ['key', 'int']])
+ val = fn(req.args, {'dom' : self.dom.id})
+ req.setResponseCode(http.ACCEPTED)
+ req.setHeader("Location", "%s/.." % req.prePathURL())
+ return val
+
def op_destroy(self, op, req):
fn = FormFn(self.xd.domain_destroy,
[['dom', 'int'],
fn=set_true, default=0,
use="Print this help.")
-def sysrq(dom, req):
- server.xend_domain_shutdown(dom, 'sysrq', req)
-
def main(argv):
opts = gopts
args = opts.parse(argv)
if len(args) < 2: opts.err('Missing sysrq character')
dom = args[0]
req = ord(args[1][0])
- sysrq(dom, req)
+ server.xend_domain_sysrq(dom, req)